package com.titanrise.crm.common.utils;

import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;

public class ValidationUtil {
    public static <L, R> Function<Either<L, R>, Either<L, R>> validate(Predicate<R> predicate, L err) {
        return EitherPipeUtil.flatMap(line -> !predicate.test(line) ? Either.left(err) : Either.right(line));
    }

    public static <L, R> Function<Either<L, R>, Either<L, R>> equals(R r, L err) {
        return validate(e -> e.equals(r), err);
    }

    public static <A> Function<Either<String, A>, Either<String, A>> nonNull(String msg) {
        return validate(Objects::nonNull, msg);
    }

    public static Function<Either<String, String>, Either<String, String>> nonEmpty(String msg) {
        return validate(line -> !line.isEmpty(), msg);
    }

    public static Function<Either<String, String>, Either<String, String>> lenUpperLimit(int limit, String msg) {
        return validate(line -> line.length() <= limit, msg);
    }

    public static Function<Either<String, String>, Either<String, String>> lenLowerLimit(int limit, String msg) {
        return validate(line -> line.length() >= limit, msg);
    }

    public static Function<Either<String, String>, Either<String, Integer>> parseInt(String msg) {
        return either -> either.flatMap((line) -> {
            try {
                return Either.right(Integer.parseInt(line));
            } catch (NumberFormatException e) {
                return Either.left(msg);
            }
        });
    }

    public static Function<Either<String, Integer>, Either<String, Integer>> greaterThan(String msg, int n) {
        return validate(e -> e > n, msg);
    }

    public static Function<Either<String, Integer>, Either<String, Integer>> lessThan(String msg, int n) {
        return validate(e -> e < n, msg);
    }

    public static Either<String, String> trimThenRight(String line) {
        return Either.right(line.trim());
    }

    public static Function<Either<String, String>, Either<String, String>> matchRegex(String regex, String msg) {
        return validate(line -> line.matches(regex), msg);
    }

    public static <L, R1, R2> Function<Either<L, R1>, Either<L, Maybe<R2>>> quitWhen(Predicate<R1> predicate, Function<Either<L, R1>, Either<L, R2>> function) {
        return Functions.flow(
                EitherPipeUtil.flatMap(Functions.flow(
                        e -> predicate.test(e)
                                ? Either.right(Maybe.nothing())
                                : function.apply(Either.right(e)).map(Maybe::just)
                ))
        );
    }
}
